package featureautomate;


import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import java.util.HashMap;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ui.internal.handlers.WizardHandler.New;
import org.xtext.lts.Statemachine;



import run.LtsRunner;
import de.ovgu.featureide.core.IFeatureProject;
import de.ovgu.featureide.core.builder.ComposerExtensionClass;
import de.ovgu.featureide.fm.core.Feature;
import de.ovgu.featureide.fm.core.configuration.Configuration;
import de.ovgu.featureide.fm.core.configuration.ConfigurationReader;
import featureautomate.structure.*;
import featureautomate.tools.AdapterAutomate;
import featureautomate.tools.Tools;


public class FeatureAutomateComposer extends ComposerExtensionClass {

	private static String separateur = "/";
	
	private static String resultat = "result";
	
	private static String featureDot = "featureDot";
	
	private HashMap<String,Feature> selectedFeatures ;

	private HashMap<String,Automate> featuresAutomate;
	
	private ArrayList<String> erreurs;

	

	@Override
	public boolean initialize(IFeatureProject project) {
		if(System.getProperty("os.name").contains("Windows")){
			separateur = "\\";
		}
		boolean supSuccess =super.initialize(project);
		selectedFeatures = new HashMap<>();
		erreurs = new ArrayList<>();
		featuresAutomate = new HashMap<>();
		//fhModelBuilder = new FeatureHouseModelBuilder(project);
		if(supSuccess==false ) {
			return false;
		} else {
			return true;
		}
		
	}

	
	@Override
	public void performFullBuild(IFile config) {
		// TODO Auto-generated method stub
		//ActivatorClass.getDefault().logInfo("Debug");
		
		
		if (config == null) {
			erreurs.add("Le fichier de config est illisible !");
			return;
		}
		
		
		assert(featureProject != null) : "Invalid project given";
		
		
		final String configPath =  config.getRawLocation().toOSString();
		final String outputPath = featureProject.getBuildPath();
		
		if (configPath == null || outputPath == null)
			return;
		
		Configuration configuration = new Configuration(featureProject.getFeatureModel());
		ConfigurationReader reader = new ConfigurationReader(configuration);
		
		try {
			reader.readFromFile(config);
		} catch (CoreException e) {
			ActivatorClass.getDefault().logError(e);
		} catch (IOException e) {
			ActivatorClass.getDefault().logError(e);
		}
		
		String featureRootName = configuration.getFeatureModel().getRoot().getName();
				
		for (Feature feature : configuration.getSelectedFeatures()) {
					selectedFeatures.put(feature.getName(),feature);
		}
		
		IProject p = featureProject.getProject();
		if (p != null) {
			
			String configName = featureProject.getCurrentConfiguration().getName();
			String chemin = featureProject.getBuildFolder().getLocationURI().getPath();
			
			File root = new File(chemin).getParentFile();
			//File dir = new File(root.getAbsolutePath()+separateur+configName.substring(0, configName.indexOf('.')));
			File dir = new File(root.getAbsolutePath()+separateur+resultat);
			
			if(dir.exists()){
				SupprRep(dir);
			}
				
			boolean isCreated = dir.mkdirs();
			
			if(isCreated){
				
				String cheminFeature = root.getAbsolutePath()+separateur+"features";

				File featureRoot = new File(cheminFeature+separateur+featureRootName);
				File fileRoot = new File(featureRoot+separateur+"root.lts");
				
				if(fileRoot.exists()){
					
					Statemachine rootLts = LtsRunner.ParseLtsProgram(fileRoot.getAbsolutePath());
					
					Automate rootAuto = AdapterAutomate.adapterStatemachine(rootLts);
					
					ArrayList<String> delete = new ArrayList<>();
					for(String event : rootAuto.getEvents().keySet()){
						if(!selectedFeatures.containsKey(event)){
							delete.add(event);
						}
					}
					
					for(String s : delete){
						rootAuto.deleteEvent(s);
					}
					
					Automate tmp;
					Automate tmp2;
					Feature ftmp;
					ArrayList<Automate> childs= new ArrayList<>();
					
					for (String ev : rootAuto.getEvents().keySet()){
						childs= new ArrayList<>();
						
						ftmp = selectedFeatures.get(ev);
						
						if(ftmp.isConcrete() && ftmp.getChildren().isEmpty()){
							tmp = AdapterAutomate.adapterStatemachine(
									LtsRunner.ParseLtsProgram(
											new File(cheminFeature
											//+"\\"+ftmp.getName()).listFiles()[0]
											+separateur+ftmp.getName()+separateur+ftmp.getName()+".lts")
											.getAbsolutePath()));
							featuresAutomate.put(ev,tmp);
							
						}
						
						if(ftmp.isConcrete() && !ftmp.getChildren().isEmpty()){
							tmp = AdapterAutomate.adapterStatemachine(
									LtsRunner.ParseLtsProgram(
											new File(cheminFeature
											+separateur+ftmp.getName()+separateur+ftmp.getName()+".lts")
											.getAbsolutePath()));
							
							for(Feature f : ftmp.getChildren()){
								if(selectedFeatures.get(f.getName()) != null){
									childs.add(AdapterAutomate.adapterStatemachine(
											LtsRunner.ParseLtsProgram(
													new File(cheminFeature
													+separateur+f.getName()+separateur+f.getName()+".lts")
													.getAbsolutePath())));
								}
							}
							if(childs.size()==0){
								featuresAutomate.put(ev,tmp);
							}else{
								tmp2 = childs.get(0);
								for (int i=1; i< childs.size(); i++ ){
										tmp2 = Tools.alt(tmp2, childs.get(i));
								}
								featuresAutomate.put(ev,Tools.seq(tmp,tmp2));
							}
						}
						
						if(ftmp.isAbstract() && !ftmp.getChildren().isEmpty()){
													
							for(Feature f : ftmp.getChildren()){
								if(selectedFeatures.get(f.getName()) != null){
									childs.add(AdapterAutomate.adapterStatemachine(
											LtsRunner.ParseLtsProgram(
													new File(cheminFeature
													+separateur+f.getName()+separateur+f.getName()+".lts")
													.getAbsolutePath())));
								}
							}
							if(childs.size()==0){
								featuresAutomate.put(ev,null);
							}else{
								tmp2 = childs.get(0);
								for (int i=1; i< childs.size(); i++ ){
									tmp2 = Tools.alt(tmp2, childs.get(i));
								}
								featuresAutomate.put(ev,tmp2);
							}
						}
					}
					
					HashMap<String,Integer> nbrFeature = new HashMap<>();
					for (String s : rootAuto.getStates().keySet()){
						for (Transition tr : rootAuto.getStates().get(s).getTransitions()){
							if(nbrFeature.get(tr.getEvent().getName())== null){
								nbrFeature.put(tr.getEvent().getName(), 1);
							}else{
								nbrFeature.put(tr.getEvent().getName(),nbrFeature.get(tr.getEvent().getName())+1);
							}
						}
					}
					
					String motif = "";
					for(String s : rootAuto.getStates().keySet()){
						for(Transition tr : rootAuto.getStates().get(s).getTransitions()){
							if(nbrFeature.get(tr.getEvent().getName()) > 1){
								motif = tr.getEvent().getName()+"_n";
								while(rootAuto.getEvents().get(motif) != null){
									motif = motif +"_n";
								}
								
								rootAuto.addEvent(new Event(motif,tr.getEvent().isReset()));
								nbrFeature.put(tr.getEvent().getName(),(nbrFeature.get(tr.getEvent().getName())-1));
								featuresAutomate.put(motif, featuresAutomate.get(tr.getEvent().getName()).clone());
								
								tr.setEvent(rootAuto.getEvents().get(motif));
								}
						}
					}
					
					File dirResult = new File(dir.getAbsolutePath()+separateur+"final"+separateur);
					dirResult.mkdirs();
					
					Automate automateFinal = Tools.compose(rootAuto,featuresAutomate);
					Tools.generateDot(automateFinal, dirResult.getAbsolutePath()+separateur+"AutomateFinal.dot");
					Tools.generateLTS(automateFinal, dirResult.getAbsolutePath()+separateur+"AutomateFinal.lts");
					
					
					File dirFeatureDot = new File(dir.getAbsolutePath()+separateur+featureDot+separateur);
					dirFeatureDot.mkdirs();
					for(String s : featuresAutomate.keySet()){
						Tools.generateDot(featuresAutomate.get(s), dirFeatureDot.getAbsolutePath()+separateur+s+".dot");
					}
					Tools.generateDot(rootAuto, dirFeatureDot.getAbsolutePath()+separateur+"root.dot");
					
					//Automate x = Tools.deplieBoucle(rootAuto.clone());
					//Tools.generateDot(x, dirFeatureDot.getAbsolutePath()+separateur+"Deplieroot.dot");
					//System.out.println(automateFinal.toString());
				
				}else{
					erreurs.add("Le fichier du feature root n'existe pas !");					
				}
			}
		}
	}
	
	
	private static void SupprRep(File r) {
	    if(r.isDirectory()){
	      suppr(r);
	    }
	    r.delete();
	}
	
	private static void suppr(File r){
	    File [] fileList = r.listFiles();
	    for(int i = 0;i<fileList.length;i++){
	      if(fileList[i].isDirectory() ){
	        suppr(fileList[i]);
	        fileList[i].delete();
	      }else{
	        fileList[i].delete();
	      }
	    }
	}

	
	
	public static void main(String[] args){
		String osName = System.getProperty("os.name"); 
		System.out.println(osName.contains("Windows"));
	}

}
